﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NHibernate;
using NHibernate.Criterion;

namespace SAKS.Services.Query
{
    public class PagedFullTextSearch<Info, File> : NHibernateQueryBase<PagedResult<Info>>, IPagedQuery
    {
        public int First { get; set; }
        public int PageSize { get; set; }
        public string Key { get; set; }
        public string Colume { get; set; }
        public Guid Id { get; set; }

        public PagedFullTextSearch(ISession session):base(session){}
        public override PagedResult<Info> Execute()
        {

            var query = GetQuery();
            var list = query.List<Info>();

            return new PagedResult<Info>()
            {
                PageOfResults = list,
                TotalItems = GetCountQuery().UniqueResult<int>()
            };
        }


        private string InfoTable
        {
            get { return typeof(Info).Name; }
        }
        private string FileTable
        {
            get { return typeof(File).Name; }
        }
        private ISQLQuery GetQuery()
        {        
            string sql = GenerateSql();
            var query = Session.CreateSQLQuery(sql);
            query.SetGuid(Colume, Id);
            query.AddEntity(typeof(Info));
            return query;
        }

        private ISQLQuery GetCountQuery()
        {
            string sql = GenerateCountSql();
            var query = Session.CreateSQLQuery(sql);
            query.SetGuid(Colume, Id);
            return query;
        }

        private string GenerateCountSql()
        {
            if (Key == null) throw new ArgumentException("Key is null");
            var keys = Key.Split(' ');
            var sb = new StringBuilder();
            sb.Append("SELECT Count(*)");
            sb.Append(GetFrom());
            sb.Append(" WHERE ");
            sb.Append(GetWhere(keys));
            return sb.ToString();
        }
        private string GenerateSql()
        {
            if (Key == null) throw new ArgumentException("Key is null");
            var keys = Key.Split(' ');
            var where = GetWhere(keys);
            var sb = new StringBuilder();
            if (First == 0)
            {
                sb.Append(GetSelect(PageSize, "*"));
                sb.Append(GetFrom());
                sb.Append(" WHERE ");
                sb.Append(where);
            }
            else
            {
                sb.Append(GetSelect(First, " * "));
                sb.Append(GetFrom());
                sb.Append(" WHERE ");
                sb.Append(InfoTable + ".Id NOT IN (");
                sb.Append(GetSelect(PageSize, InfoTable + ".Id "));
                sb.Append(GetFrom());
                sb.Append("WHERE " + where);
                sb.Append(") AND ");
                sb.Append(where);
            }
            return sb.ToString();
        }

        private string GetSelect(int topcount, string select)
        {
            return " SELECT TOP " + topcount + " " + select;
        }
        private string GetFrom()
        {
            return " FROM " + InfoTable + " INNER JOIN " + FileTable + " ON " + InfoTable + ".FileId = " + FileTable + ".Id ";
        }
        private string GetWhere(string[] keys)
        {
            StringBuilder sb = new StringBuilder();
            sb.Append(FileTable + "." + Colume + " = :" + Colume + " AND ");
            sb.Append("Contains(" + FileTable + ".Doc,\'");
            sb.Append("\"" + keys[0] + "\"");
            var length = keys.Count();
            if (length > 1)
            {
                for (int i = 1; i < length; i++)
                    sb.Append(" and \"" + keys[i] + "\"");
            }
            sb.Append("\')");
            return sb.ToString();
        }

    }
}
